package com.wsd.jing.aspect;

import cn.dev33.satoken.stp.StpUtil;
import com.wsd.jing.annotation.ControllerLog;
import com.wsd.jing.entity.BusinessLog;
import com.wsd.jing.service.IBusinessLogService;
import com.wsd.jing.utils.IpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * All rights Reserved, Designed By www.tom.com
 *
 * @author tom
 * @version 1.0.0
 * @projectName: jing
 * @packageName: com.wsd.jing.aspect
 * @className: ControllerLogAspect
 * @description 记录controller请求切面
 * @createDate 2022/12/6 16:30
 * @copyright 2022/12/6 16:30 www.tom.com Inc. All rights reserved.
 */
@Slf4j
@Component
@Aspect
@RequiredArgsConstructor
public class ControllerLogAspect {
    private final IBusinessLogService businessLogService;

    @Value("${log.business}")
    private Boolean business;

    @Pointcut("@annotation(com.wsd.jing.annotation.ControllerLog)")
    public void controllerLog() {
    }

    @Around("controllerLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = null;
        ControllerLog annotation = getAnnotation(point);
        HttpServletRequest request = getRequest();
        String ip = IpUtil.getIp(request);
        String location = IpUtil.getRegion(ip);
        long start = System.currentTimeMillis();
        result = point.proceed();
        long time = System.currentTimeMillis() - start;
        if (business) {
            BusinessLog businessLog = new BusinessLog();
            businessLog.setIp(ip);
            businessLog.setLocation(location);
            businessLog.setTime(time);
            businessLog.setCreateTime(LocalDateTime.now());
            businessLog.setAccount(StpUtil.isLogin() ? StpUtil.getLoginId().toString() : "");
            businessLog.setMethod(request.getMethod());
            businessLog.setParams(getParams(point).toString());
            businessLog.setModule(annotation.action());
            businessLog.setUri(request.getRequestURI());
            businessLog.setResult(result.toString());
            businessLogService.save(businessLog);
        }

        return result;
    }

    /**
     * @param :
     * @return HttpServletRequest
     * @author tom
     * @description 获取请求HttpServletRequest对象
     * @createDate 2022/12/6 17:09
     */
    private HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return requestAttributes.getRequest();
    }

    /**
     * @param point:
     * @return BusinessLog
     * @author tom
     * @description 获取注解信息
     * @createDate 2022/12/6 17:20
     */
    private ControllerLog getAnnotation(ProceedingJoinPoint point) {
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        return method.getAnnotation(ControllerLog.class);
    }

    /**
     * @param point:
     * @return Object
     * @author tom
     * @description 获取请求参数
     * @createDate 2022/12/6 17:30
     */
    private Object getParams(ProceedingJoinPoint point) {
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        // 参数名
        String[] names = methodSignature.getParameterNames();
        // 参数值
        Object[] values = point.getArgs();
        Map<String, Object> params = new LinkedHashMap<>();
        for (int i = 0; i < names.length; i++) {
            Object value = values[i];
            if (value instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) value;
                value = file.getOriginalFilename();
            }
            params.put(names[i], value);
        }
        return params;
    }
}
